"""
基础API类测试

测试BaseAPI类的核心功能，包括请求发送、响应处理、异常处理等。
使用mock来模拟HTTP请求，避免实际调用外部API。
"""

import unittest
from unittest.mock import patch, MagicMock
import json
from cn_api_adapters.common.base import BaseAPI
from cn_api_adapters.common.exceptions import APIError, AuthenticationError, RequestError


class TestBaseAPI(unittest.TestCase):
    """测试BaseAPI类的功能"""
    
    def setUp(self):
        """设置测试环境"""
        self.base_url = "https://api.example.com"
        self.api = BaseAPI(
            base_url=self.base_url,
            timeout=30,
            max_retries=3,
            retry_delay=1,
            debug=False
        )
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_get_request_success(self, mock_request):
        """测试GET请求成功的情况"""
        # 模拟成功响应
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"success": True, "data": "test"}
        mock_request.return_value = mock_response
        
        # 执行GET请求
        response = self.api.get("/test")
        
        # 验证结果
        self.assertEqual(response, {"success": True, "data": "test"})
        mock_request.assert_called_once_with(
            "GET",
            f"{self.base_url}/test",
            timeout=30,
            proxies=None,
            headers={},
            json=None,
            data=None,
            params=None
        )
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_post_request_success(self, mock_request):
        """测试POST请求成功的情况"""
        # 模拟成功响应
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"success": True, "message": "Created"}
        mock_request.return_value = mock_response
        
        # 执行POST请求
        data = {"key": "value"}
        response = self.api.post("/create", json=data)
        
        # 验证结果
        self.assertEqual(response, {"success": True, "message": "Created"})
        mock_request.assert_called_once()
        self.assertEqual(mock_request.call_args[1]['json'], data)
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_request_http_error(self, mock_request):
        """测试HTTP错误处理"""
        # 模拟404错误
        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_response.text = "Not Found"
        mock_request.return_value = mock_response
        
        # 验证抛出APIError异常
        with self.assertRaises(APIError) as context:
            self.api.get("/not-found")
        
        self.assertIn("404", str(context.exception))
        self.assertIn("Not Found", str(context.exception))
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_request_authentication_error(self, mock_request):
        """测试认证错误处理"""
        # 模拟401错误
        mock_response = MagicMock()
        mock_response.status_code = 401
        mock_response.text = "Unauthorized"
        mock_request.return_value = mock_response
        
        # 验证抛出AuthenticationError异常
        with self.assertRaises(AuthenticationError) as context:
            self.api.get("/protected")
        
        self.assertIn("401", str(context.exception))
        self.assertIn("Unauthorized", str(context.exception))
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_request_connection_error(self, mock_request):
        """测试连接错误处理"""
        # 模拟连接错误
        from requests.exceptions import ConnectionError
        mock_request.side_effect = ConnectionError("Connection refused")
        
        # 验证抛出RequestError异常
        with self.assertRaises(RequestError) as context:
            self.api.get("/test")
        
        self.assertIn("Connection refused", str(context.exception))
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_request_timeout(self, mock_request):
        """测试请求超时处理"""
        # 模拟超时错误
        from requests.exceptions import Timeout
        mock_request.side_effect = Timeout("Request timed out")
        
        # 验证抛出RequestError异常
        with self.assertRaises(RequestError) as context:
            self.api.get("/test")
        
        self.assertIn("Request timed out", str(context.exception))
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_handle_response_invalid_json(self, mock_request):
        """测试处理无效JSON响应"""
        # 模拟无效JSON响应
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.text = "Invalid JSON"
        mock_response.json.side_effect = json.JSONDecodeError("Expecting property name", "Invalid JSON", 0)
        mock_request.return_value = mock_response
        
        # 验证返回原始文本
        response = self.api.get("/invalid-json")
        self.assertEqual(response, "Invalid JSON")
    
    @patch('cn_api_adapters.common.base.requests.request')
    def test_retry_mechanism(self, mock_request):
        """测试重试机制"""
        # 第一次调用失败，第二次调用成功
        mock_response_success = MagicMock()
        mock_response_success.status_code = 200
        mock_response_success.json.return_value = {"success": True}
        
        mock_response_fail = MagicMock()
        mock_response_fail.status_code = 500
        mock_response_fail.text = "Internal Server Error"
        
        # 设置side_effect，第一次失败，第二次成功
        mock_request.side_effect = [mock_response_fail, mock_response_success]
        
        # 创建一个重试次数为1的API实例
        api_with_retry = BaseAPI(
            base_url=self.base_url,
            max_retries=1,
            retry_delay=0
        )
        
        # 执行请求，应该会重试一次
        response = api_with_retry.get("/test")
        
        # 验证结果和调用次数
        self.assertEqual(response, {"success": True})
        self.assertEqual(mock_request.call_count, 2)  # 应该调用了两次
    
    def test_build_url(self):
        """测试URL构建"""
        # 测试相对路径
        url1 = self.api._build_url("/test")
        self.assertEqual(url1, f"{self.base_url}/test")
        
        # 测试已经是完整URL的情况
        full_url = "https://example.com/direct"
        url2 = self.api._build_url(full_url)
        self.assertEqual(url2, full_url)
        
        # 测试没有前导斜杠的路径
        url3 = self.api._build_url("test")
        self.assertEqual(url3, f"{self.base_url}/test")


if __name__ == '__main__':
    unittest.main()